/**
 * **************************************************************************
 *
 * @说明: 
 * @项目名称: talent-aio-examples-server
 *
 * @author: tanyaowu 
 * @创建时间: 2016年11月18日 上午9:15:03
 *
 * **************************************************************************
 */
package com.talent.proxy.mysql.common;

import java.nio.ByteBuffer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.talent.aio.common.ChannelContext;
import com.talent.aio.common.exception.AioDecodeException;
import com.talent.aio.common.intf.Packet;
import com.talent.proxy.mysql.common.json.Json;
import com.talent.proxy.mysql.common.utils.BufferUtil;

/**
 * 
 * @author tanyaowu 
 * @创建时间 2016年11月18日 上午9:15:03
 *
 * @操作列表
 *  编号	| 操作时间	| 操作人员	 | 操作说明
 *  (1) | 2016年11月18日 | tanyaowu | 新建类
 *
 */
public abstract class MysqlPacket extends Packet
{
	private static Logger log = LoggerFactory.getLogger(MysqlPacket.class);
	public static final long NULL_LENGTH = -1;
	public static final byte[] EMPTY_BYTES = new byte[0];
	/**
	 * 消息头长
	 */
	public static final int HEADER_SIZE = 4;

	public int bodySize;

	public byte seqId;

	/**
	 * 编码时，返回消息体的字节数
	 * @return
	 *
	 * @author: tanyaowu
	 * @创建时间:　2017年1月22日 下午8:24:00
	 *
	 */
	public abstract int bodySize();

	/**
	 * 消息简单的描述
	 * @return
	 *
	 * @author: tanyaowu
	 * @创建时间:　2017年1月22日 下午8:24:34
	 *
	 */
	protected abstract String packetDesc();

	public MysqlPacket decode(ByteBuffer buffer, ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext) throws AioDecodeException
	{
		MysqlPacket packet = decodeWithoutLog(buffer, channelContext);

		if (packet != null)
		{
			if (isCompletePacket())
			{
				try
				{
					MysqlExt mysqlExt = channelContext.getSessionContext();
					mysqlExt.getSeq().incrementAndGet();
					log.error("{} {}:{}", mysqlExt.getSeq().get(), this.getClass().getSimpleName(), Json.toJson(this));
				} catch (Exception e)
				{
					log.error(e.getMessage(), e);
				}
			}
		}

		return packet;
	}

	public MysqlPacket decodeWithoutLog(ByteBuffer buffer, ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext) throws AioDecodeException
	{
		//		int initPosition = buffer.position();
		int readableLength = buffer.limit() - buffer.position();
		if (readableLength < MysqlPacket.HEADER_SIZE)
		{
			return null;
		}

		bodySize = BufferUtil.readUB3(buffer);
		if (readableLength < (MysqlPacket.HEADER_SIZE + bodySize))
		{
			return null;
		}

		seqId = BufferUtil.read(buffer);
		decodeBody(buffer, channelContext);

		return this;
	}

	public boolean isCompletePacket()
	{
		return true;
	}

	/**
	 * 解码消息体
	 * @param buffer
	 * @param channelContext
	 * @throws AioDecodeException
	 *
	 * @author: tanyaowu
	 * @创建时间:　2017年1月22日 下午8:24:54
	 *
	 */
	public abstract void decodeBody(ByteBuffer buffer, ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext) throws AioDecodeException;

	/**
	 * 对消息进行编码
	 * @param channelContext
	 * @return
	 *
	 * @author: tanyaowu
	 * @创建时间:　2017年1月22日 下午8:25:14
	 *
	 */
	public abstract ByteBuffer encode(ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext);

	/**
	 * 收到消息时要作的处理
	 * @param channelContext
	 * @return
	 *
	 * @author: tanyaowu
	 * @创建时间:　2017年1月22日 下午8:29:45
	 *
	 */
	public abstract MysqlReturn onReceived(ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext);

	@Override
	public String toString()
	{
		return new StringBuilder().append(packetDesc()).append("{bodySize:").append(bodySize).append(",packetId:").append(seqId).append('}').toString();
	}

	//	public Integer getSynSeq()
	//	{
	//		return packetId & 0xFF;
	//	}
	//	
	//	/**
	//	 * @param synSeq the synSeq to set
	//	 */
	//	public void setSynSeq(Integer synSeq)
	//	{
	//		if (synSeq != null)
	//		{
	//			this.packetId = synSeq.byteValue();	
	//		}
	//	}

}
